/*=+--+=#=+--     Unmanned Aerial System Management Software      --+=#=+--+=#*\
|          Copyright (C) 2011 Regents of the University of Colorado.           |
|                             All Rights Reserved.                             |

     This program is free software: you can redistribute it and/or modify
     it under the terms of the GNU General Public License version 2 as
     published by the Free Software Foundation.

     This program is distributed in the hope that it will be useful,
     but WITHOUT ANY WARRANTY; without even the implied warranty of
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     GNU General Public License for more details.

     You should have received a copy of the GNU General Public License
     along with this program.  If not, see <http://www.gnu.org/licenses/>.

            Jack Elston                       Cory Dixon                        
|           elstonj@colorado.edu              dixonc@colorado.edu              |
|                                                                              |
\*=+--+=#=+--                 --+=#=+--+=#=+--                    --+=#=+--+=#*/

/*!
  \file nodeList.cxx
  \author Cory Dixon
*/

#include <stdlib.h>
#include <stdio.h>

#include "vcConfig.h"
#include "clientList.h"
#include "nodeWindow.h"

//--- include all page headers here --//
#include "commPage.h"
#include "telemPage.h"
#include "gpsPage.h"
#include "chainPage.h"
#include "pthPage.h"
#include "trackPage.h"
#include "pasPage.h"
#include "antPage.h"
#include "joystickPage.h"
#include "dmPage.h"

extern GuiStruct  guiStr;
extern bool gw_joy;

typedef struct {
	int cmd;
	int page;
} WindowMapping;

//--- map the page to its appropriate capabilities command ---//
WindowMapping cmdToPage[NUM_PAGES] = {
	{CMD_TELEM,         TELEM_PAGE},	
	{CMD_SONDE,         PTH_PAGE},	
	{CMD_CHAIN,         CHAINING_PAGE},	
	{CMD_LINK_STATUS,   COMM_PAGE},	
	{CMD_GPS_TELEM,     GPS_PAGE},
	{CMD_TRACK,         TRACK_PAGE},
	{CMD_SERVO,         JOYSTICK_PAGE},
	{CMD_ANT_PAS_TELEM, PAS_PAGE},
	{CMD_ANT_APS_TELEM, ANT_PAGE},
	{CMD_DEPLOY_STATUS, DM_PAGE}
};

NodeWindow::NodeWindow()
{
	//--- define all page variables here --//
	node_pages[TELEM_PAGE]    = new TelemPage;
	node_pages[PTH_PAGE]      = new PTHPage;
	node_pages[CHAINING_PAGE] = new ChainPage;
	node_pages[COMM_PAGE]     = new CommPage;
	node_pages[GPS_PAGE]      = new GPSPage;
	node_pages[TRACK_PAGE]    = new TrackPage;
	node_pages[JOYSTICK_PAGE] = new JoystickPage;
	node_pages[PAS_PAGE]      = new PasPage;
	node_pages[ANT_PAGE]      = new AntPage;
	node_pages[DM_PAGE]       = new DMPage;

	node_win = NULL;
	notebook = NULL;
	client   = NULL;
	builder  = NULL;
}

NodeWindow::~NodeWindow()
{
	if( node_win ) {
		gtk_widget_destroy(node_win);
		g_object_unref (G_OBJECT (builder));
		node_win = NULL;
	}
	for( int i=0; i < NUM_PAGES; i++) {
		if( node_pages[i] ) delete node_pages[i];
		node_pages[i] = NULL;
	}
}

void NodeWindow::create_node_window(Client *win_client)
{
	if( !win_client )
		return;
	client = win_client;

	//-- get the window definition file and load builder
	ui_file = guiStr.config.node_ui_file;
	builder = gtk_builder_new ();
	gtk_builder_add_from_file (builder, ui_file.c_str(), NULL);

	//-- get the window 
	node_win = GTK_WIDGET (gtk_builder_get_object (builder, "node_window"));
	if( !node_win ) {
		cout << "NodeWindow::create_node_window - invalid xml file, no `node_window` defined" << endl;
		g_object_unref (G_OBJECT (builder));
		return;
	}
	//-- get the notebook
	notebook = GTK_WIDGET (gtk_builder_get_object (builder, "notebook"));
	if( !notebook ) {
		cout << "NodeWindow::create_node_window - invalid xml file, no `notebook` defined" << endl;
		g_object_unref (G_OBJECT (builder));
		return;
	}
	
	String title = client->name;
	title += " [";
	title += inet_ntoa(client->address[0]);
	title += "]";
	gtk_window_set_title(GTK_WINDOW(node_win), title.c_str());

	//-- now we need to create all of the pages, eventhough we 
	//   may not use them. This is for dynamic reasons of adding new 
	//   capabilities

	//-- now loop through the notebook and display the pages based on the current value of the 
	for(int p_ind = 0; p_ind < NUM_PAGES; p_ind++) {
		// create the page
		if( node_pages[p_ind] ) node_pages[p_ind]->create_page( client, builder);

		GtkWidget *page = gtk_notebook_get_nth_page( GTK_NOTEBOOK(notebook), cmdToPage[p_ind].page);
		if(client->capabilities.find(cmdToPage[p_ind].cmd)) 
			if(p_ind == JOYSTICK_PAGE && !gw_joy) {  // THIS IS DIFFERENT, NEEDS GS SUPPORT
				gtk_widget_hide(page);
			}
			else
				gtk_widget_show(page);
		else 
			gtk_widget_hide(page);
	}
	
	//-- signal for deleting window, we actually don't delete it, just hide
	gtk_signal_connect(GTK_OBJECT(node_win), "delete_event", GTK_SIGNAL_FUNC(NodeWindow::node_window_destroy), node_win);

	// finally, setup timer to refresh the list
	g_timeout_add (250, NodeWindow::timeout_cb, this);
}

gboolean NodeWindow::node_window_destroy(GtkWidget * widget, GdkEventKey * event, gpointer user_data)
{
	if( user_data ) {
		gtk_widget_hide(GTK_WIDGET(user_data));
		return TRUE;
	}
	return FALSE;
}


void NodeWindow::update_window()
{
	//cout << " NodeWindow::update_window() - " << endl;

	// don't do work if we don't need too
	if( !node_win || !GTK_WIDGET_VISIBLE( node_win ) ) {
		return;
	}

	//cout << "NodeWindow::update_window - mutex_lock" << endl;
	guiStr.vcgui->mutex_lock();

	//-- now loop through the notebook and update the values
	for(int p_ind = 0; p_ind < NUM_PAGES; p_ind++) {
		GtkWidget *page = gtk_notebook_get_nth_page( GTK_NOTEBOOK(notebook), cmdToPage[p_ind].page);

		if(client->capabilities.find(cmdToPage[p_ind].cmd)) 
		{
			// make sure the pages is shown
			if(p_ind == JOYSTICK_PAGE && !gw_joy) {  // THIS IS DIFFERENT, NEEDS GS SUPPORT
				gtk_widget_hide(page);
			} else { 
			if( !GTK_WIDGET_VISIBLE(page) )
				gtk_widget_show(page);

			if( node_pages[p_ind] ) 
				node_pages[p_ind]->update();
			}
		}
		else
			gtk_widget_hide(page);
	}

	guiStr.vcgui->mutex_unlock();
	//cout << "NodeWindow::update_windows - mutex_unlock" << endl;

	gtk_widget_queue_draw( node_win );
}

gboolean NodeWindow::timeout_cb(gpointer user_data)
{
	//cout << "NodeWindow::timeout_cb - user_data=" << user_data << endl;

	NodeWindow *win = (NodeWindow *)user_data;
	if( !win )
		return false;

	win->update_window();
	
	return TRUE;
}

// use this function to indicate a command or ACK has been received
void NodeWindow::setCMD_RX(uint8_t cmd_id, int ack_nack)
{
	//cout << "NodeWindow::setCMD_RX - name=" << name << " [" << (int)cmd_id << "]  ackNack=" << ack_nack << endl;
	
	for( int i=0; i < NUM_PAGES; i++) {
		if( node_pages[i] ) 
			node_pages[i]->setCMD_RX(cmd_id, ack_nack);
	}

}
